package com.lin.benchmade.pinyin;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * 拼音字典和一个拼音前缀的字典。
 * 根据数据源的所有汉字，构建一个字典，在搜索时，对拼音进行拼音-汉字的转换，转换的规则就是通过拆分好的拼音，到这个字典中匹配，返回对应的汉字
 * 
 * @author xiaolin
 */
public class PinyinIndexDictionary {

	public  Map<String, List<Node>> prefixMap_dic = new HashMap<String, List<Node>>();
	private final Map<String, List<Node>> pinyin_dic = new HashMap<String, List<Node>>();
	private final short threshold = 1;

	/**
	 * 将一个String添加到这个字典中
	 * 
	 * @param value
	 */
	public void addItem(String[] pinyinArray, char[] charArray) {
		for (int i = 0; i < pinyinArray.length; i++) {
			if (pinyinArray[i] != null) {
				if (pinyin_dic.get(pinyinArray[i]) == null) {
					List<Node> list = new ArrayList<Node>(128);
					list.add(new Node(charArray[i], 1));
					pinyin_dic.put(pinyinArray[i], list);
				} else {
					List<Node> list = pinyin_dic.get(pinyinArray[i]);
					int pos = list.indexOf(new Node(charArray[i], 1));
					if (pos == -1) {
						list.add(new Node(charArray[i], 1));
					} else {
						Node h = list.get(pos);
						h.setNum(h.getNum() + 1);
					}
				}
			}
		}
	}

	/**
	 * 由CHINESE_DIC转换成一个前缀拼音map 之前一直是用树做前缀匹配，输入一个“d”
	 * 得到所有d开头的树的字典序列，这样每次搜素，都要遍历部分的树。现在把所有的前缀都初始化好，用空间换一点时间。 因为拼音不多，所以占用空间应该不大
	 */
	public void converterAndSort() {
		/**
		 * 前缀map，是根据完全拼音的dic解析而来。
		 */
		for (Entry<String, List<Node>> entry : pinyin_dic.entrySet()) {
			Collections.sort(entry.getValue());// 先对CHINESE_DIC中的list排序，应为是引用，所以不用再add一次。
			char[] keyArray = entry.getKey().toCharArray();
			for (int i = 1; i <= keyArray.length; i++) {// 取出key，如"guan" 取出
														// g、gu、gua、guan
				String prefix = new String(keyArray, 0, i);
				if (prefixMap_dic.get(prefix) == null) {// 如果map是空的，说明还没有这个前缀的entry
					List<Node> perfixList = new ArrayList<Node>(50);
					for (Entry<String, List<Node>> childEntry : pinyin_dic.entrySet()) {
						if (childEntry.getKey().startsWith(prefix)) {
							List<Node> list = childEntry.getValue();
							for(Node n : list){
								if(n.getNum()>threshold){
									perfixList.add(n);
								}
							}
						}
					}
					Collections.sort(perfixList);
					prefixMap_dic.put(prefix, perfixList);
				}
			}
			// prefixMap.put(entry.getKey(), entry.getValue());
		}
	}

	public List<PinyinIndexDictionary.Node> match(String pinyin) {
		return pinyin_dic.get(pinyin);
	}

	public List<PinyinIndexDictionary.Node> matchPerfix(String pinyin) {
		return prefixMap_dic.get(pinyin);
	}
	
	public void close(){
		prefixMap_dic.clear();
		pinyin_dic.clear();
	}

	/**
	 * 为了排序和可比较，所以创建了一个内部类。保存一个汉字和这个汉字出现的次数
	 * @author xiaolin
	 */
	public final class Node implements Comparable<Node> {
		private char value;
		private int num;
		private Set<String> prefixPinYin;

		public Node(char value, int num) {
			this.value = value;
			this.num = num;
		}

		public char getValue() {
			return value;
		}

		public void setValue(char value) {
			this.value = value;
		}

		public int getNum() {
			return num;
		}

		public void setNum(int num) {
			this.num = num;
		}

		public Set<String> getPrefixPinYin() {
			return prefixPinYin;
		}

		public void setPrefixPinYin(Set<String> prefixPinYin) {
			this.prefixPinYin = prefixPinYin;
		}

		@Override
		public boolean equals(Object obj) {
			Node n = (Node) obj;
			return this.value == n.value;
		}

		@Override
		public String toString() {
			return this.value + " " + this.num;
		}

		@Override
		public int compareTo(Node o) {
			Node h1 = o;
			if (this.num == h1.num) {
				return 0;
			} else if (this.num > h1.num) {
				return -1;
			} else {
				return 1;
			}
		}
	}
}
